﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace WpfApp3SingleObjectBinding
{
    public class ObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;

        protected virtual void OnPropertyChanged(string propName)
        {
            // 属性名拼写错误或后来更改，可能导致细微的错误
            // 方式一：检查该属性名称是否存在
            //Type type = GetType();
            //PropertyInfo? propertyInfo = type.GetProperty(propName);
            //Debug.Assert(propertyInfo != null);

            var pc = PropertyChanged;
            if (pc != null)
            {
                pc(this, new PropertyChangedEventArgs(propName));
            }
        }
        /// <summary>
        /// 属性名拼写错误或后来更改，可能导致细微的错误
        /// 方式二：在一个公共方法中进行不等式检查。更进一步的改进是
        /// 不指定实际属性名称，而是让代码自动推断它。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="field"></param>
        /// <param name="value"></param>
        /// <param name="expr"></param>
        protected void SetProperty<T>(ref T field, T value,
            Expression<Func<T>> expr)
        {
            if (!EqualityComparer<T>.Default.Equals(field, value))
            {
                field = value;
                var lambda = (LambdaExpression)expr;
                MemberExpression? memberExpr = null;
                if (lambda.Body is UnaryExpression)
                {
                    // 一元运算表达式
                    var unaryExpr = lambda.Body as UnaryExpression;
                    memberExpr = unaryExpr.Operand as MemberExpression;
                }
                else
                {
                    memberExpr = lambda.Body as MemberExpression;
                }

                if (memberExpr != null)
                    OnPropertyChanged(memberExpr.Member.Name);
            }
        }

        protected void SetProperty<T>(ref T field, T value,
            [CallerMemberName] string propName = null)
        {
            if (!EqualityComparer<T>.Default.Equals(field, value))
            {
                field = value;
                var pc = PropertyChanged;
                if (pc != null)
                    pc(this, new PropertyChangedEventArgs(propName));
            }
        }
    }
}
